import logging
import threading

from PyQt5.QtBluetooth import QLowEnergyService, QLowEnergyCharacteristic, QLowEnergyDescriptor, QLowEnergyController, \
    QBluetoothUuid
from PyQt5.QtCore import pyqtSignal, QEvent, QObject, QTimer, QByteArray
from PyQt5.QtWidgets import QWidget

from common import get_widget
from widget.characteristic_node_widget import CharacteristicNodeWidget
from widget.service_node_widget_ui import Ui_ServiceNodeWidget
from widget.node_content_widget import NodeContentWidget

service_widget_css = """
QWidget#serviceWidget::hover{
    background-color: #E5F3FF;
 }
 QWidget#serviceWidget{
    background-color: yellow;
 }
"""


class ServiceNodeWidget(QWidget, Ui_ServiceNodeWidget):
    service_update = pyqtSignal()
    clicked = pyqtSignal(int)

    def __init__(self, control: QLowEnergyController, service: QLowEnergyService, parent: NodeContentWidget, index, *args,
                 **kwargs):
        super(ServiceNodeWidget, self).__init__(*args, **kwargs)
        self.setupUi(self)
        self._control = control
        self._service: QLowEnergyService = None
        self._parent = parent
        self._service_name = ''
        self._service_uuid = 0
        self._index = index
        self._signal_init()
        self.main_widget = get_widget('main_widget')
        self.service = service
        self.characteristic_widget_list = []
        self.characteristic_sub_widget = NodeContentWidget(self._parent)
        self.characteristic_sub_widget.title_name = "{}->Characteristic List".format(service.serviceName())
        self.characteristic_sub_widget.setObjectName("characterSubWidget")
        self._parent.insert_item_to_child_area(self.characteristic_sub_widget)

        # 服务node ui放进来，用于后续处理
        self.service_node_list = []
        # 把一个个服务节点ui加进来，形成的服务列表widget
        self.service_node_list_widget = NodeContentWidget(self._parent)
        self.service_node_list_widget.title_name = "{}->Service List".format(service.serviceName())
        self.service_node_list_widget.setObjectName("subServiceSubWidget")
        self._parent.insert_item_to_child_area(self.service_node_list_widget)
        self._service_signal_init()
        self._custom_ui()

    def _signal_init(self):
        self.service_update.connect(self.service_update_display)

    def _custom_ui(self):
        self.installEventFilter(self)
        self.setObjectName("serviceWidget")
        self.setAutoFillBackground(True)
        self.setStyleSheet("QWidget#serviceWidget { background-color: yellow }")  # 没起作用
        self.service_update_display()

    def _service_signal_init(self):
        self.service.characteristicChanged.connect(self.on_characteristic_changed)
        self.service.characteristicRead.connect(self.on_characteristic_read)
        self.service.characteristicWritten.connect(self.on_characteristic_written)
        self.service.descriptorRead.connect(self.on_descriptor_read)
        self.service.descriptorWritten.connect(self.on_descriptor_written)
        self.service.error.connect(self.on_error)
        self.service.stateChanged.connect(self.on_state_changed)

    def eventFilter(self, ob: QObject, event: QEvent) -> bool:
        if event.type() == QEvent.MouseButtonDblClick and self.service.state() == QLowEnergyService.ServiceDiscovered:
            print("double clicked：" + self.service.serviceName())
            self.characteristic_sub_widget.item_double_clicked()
            self.clicked.emit(self._index)
        return super().eventFilter(ob, event)

    @property
    def service(self):
        return self._service

    @service.setter
    def service(self, service):
        self._service = service
        # discover_details_thread = threading.Thread(target=self.service_discover_details_entry)
        # discover_details_thread.start()

    def service_discover_details_entry(self):
        self.start_discover_details()
        print("service_discover_details_entry finish")

    def start_discover_details(self):
        self.main_widget.msg_print("{}:start discover details".format(self.service.serviceName()))
        self.service.discoverDetails()

    def on_characteristic_changed(self, characteristic: QLowEnergyCharacteristic, value):
        """
        接收通知的槽函数, 对clientCharactericConfigurtion描述都写1使能notify
        :param characteristic:
        :param value:
        :return:
        """
        print("on_characteristic_changed:")

    def on_characteristic_read(self, characteristic: QLowEnergyCharacteristic, value: QByteArray):
        """
        执行readCharacteristic后调用这个
        :param characteristic:
        :param value:
        :return:
        """
        try:
            print("on_characteristic_read:" + str(value))
            widget: CharacteristicNodeWidget = self.get_widget_from_characteristic(characteristic)
            widget.set_value_text(value)
        except Exception as e:
            print(e)

    def on_characteristic_written(self, characteristic: QLowEnergyCharacteristic, value):
        print("on_characteristic_written:" + str(value))

    def on_descriptor_read(self, descriptor: QLowEnergyDescriptor, value):
        print('on_descriptor_read')

    def on_descriptor_written(self, descriptor: QLowEnergyDescriptor, value):
        """
         writeDescriptor之后会进入这个槽函数
        :param descriptor:
        :param value:
        :return:
        """
        print("on_descriptor_written：" + str(value))

    def on_state_changed(self, new_state):
        self.main_widget.msg_print("{}:on_state_changed".format(self.service.serviceName()))
        if new_state == QLowEnergyService.InvalidService:
            self.state_value_lb.setText("InvalidService:失去连接后重新连接,依然无效")
        elif new_state == QLowEnergyService.DiscoveryRequired:
            self.state_value_lb.setText("DiscoveryRequired:已经调用discoverDetails()发现更多服务细节")
        elif new_state == QLowEnergyService.DiscoveringServices:
            self.state_value_lb.setText("DiscoveringServices:正在发现服务的详细信息。")
        elif new_state == QLowEnergyService.ServiceDiscovered:
            self.state_value_lb.setText("ServiceDiscovered:已发现服务的详细信息。")
            self.main_widget.msg_print("now can read/write characteristic")
            self.create_characteristic_widget()
        elif new_state == QLowEnergyService.LocalService:
            self.state_value_lb.setText("LocalService:服务与外设角色的控制器对象相关联,状态不会改变")
        else:
            self.state_value_lb.setText("No State")

    def on_error(self, new_error):
        if new_error == QLowEnergyService.NoError:
            self.error_value_lb.setText("No error has occurred.")
        elif new_error == QLowEnergyService.OperationError:
            self.error_value_lb.setText("OperationError.")
        elif new_error == QLowEnergyService.CharacteristicReadError:
            self.error_value_lb.setText("CharacteristicReadError.")
        elif new_error == QLowEnergyService.CharacteristicWriteError:
            self.error_value_lb.setText("CharacteristicWriteError.")
        elif new_error == QLowEnergyService.DescriptorReadError:
            self.error_value_lb.setText("DescriptorReadError.")
        elif new_error == QLowEnergyService.DescriptorWriteError:
            self.error_value_lb.setText("DescriptorWriteError.")
        elif new_error == QLowEnergyService.UnknownError:
            self.error_value_lb.setText("UnknownError.")
        else:
            self.error_value_lb.setText("Not found")

    def service_update_display(self):
        try:
            self.main_widget.msg_print("{}:Display service on screen".format(self.service.serviceName()))
            self.service_name_lb.setText(self.service.serviceName())
            # 状态显示
            self.on_state_changed(self.service.ServiceState)
            # 显示UUID
            self.service_uuid_value_lb.setText("{:#X}".format(self.service.serviceUuid().toUInt16()[0]))
            # 显示服务类型
            if self.service.ServiceType == QLowEnergyService.PrimaryService:
                self.service_type_lb.setText("Primary Service")
            else:
                self.service_type_lb.setText("Included Service")
                uuid_list = self.service.includedServices()
                for uuid in uuid_list:
                    print("Included Service:" + uuid.toString())
                # self.add_service_to_list(self.service)   # TODO:把controller传入进来继续创建服务
            # 显示错误
            self.on_error(self.service.ServiceError)
        except Exception as e:
            print(e)

    def create_characteristic_widget(self):
        characteristics = self.service.characteristics()
        for characteristic in characteristics:
            self.add_characteristic_to_list(characteristic)
        uuids = self.service.includedServices()
        print("service number:" + str(len(uuids)))
        for uuid in uuids:
            service = self._control.createServiceObject(uuid)  # TODO:服务中包含服务应该加在哪？
            service_widget = ServiceNodeWidget(self._control, service, self.service_node_list_widget, len(self.service_node_list))
            self.service_node_list.append(service_widget)
            self.service_node_list_widget.insert_item_to_parent_area(service_widget)

    def add_characteristic_to_list(self, characteristic):
        try:
            widget = CharacteristicNodeWidget(self.service, characteristic, self.characteristic_sub_widget,
                                              len(self.characteristic_widget_list))
            # widget.read_requested.connect(self.on_characteristic_read_request)
            # widget.write_requested.connect(self.on_characteristic_write_request)
            self.characteristic_sub_widget.insert_item_to_parent_area(widget)
            self.characteristic_widget_list.append(widget)
        except Exception as e:
            print(e)

    def get_characteristic_from_index(self, index) -> QLowEnergyCharacteristic:
        for count, widget in enumerate(self.characteristic_widget_list):
            if count == index:
                return widget.characteristic
        return None

    def get_widget_from_characteristic(self, characteristic: QLowEnergyCharacteristic) -> CharacteristicNodeWidget:
        for count, widget in enumerate(self.characteristic_widget_list):
            if widget.characteristic == characteristic:
                return widget
        return None

    def enable_mccr_notify(self):
        self.service.characteristic()

